//
//  MyDocument.m
//  Secret Santa
//
//  Created by Andrew Cain on 12/10/07.
//  Copyright __MyCompanyName__ 2007 . All rights reserved.
//

#include <stdlib.h>
#include <Message/NSMailDelivery.h>

#import "MyDocument.h"
#import "SSPerson.h"
#import "SSChristmas.h"

#define MyPrivateTableViewDataType @"MyPrivateTableViewDataType"

@implementation MyDocument

- (id)init 
{
    self = [super init];
    if (self != nil) {
        // initialization code
		statusMessages = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void) dealloc
{
	[statusMessages release];
	[super dealloc];
}

- (void)awakeFromNib
{
	[personTableView registerForDraggedTypes: [NSArray arrayWithObject:MyPrivateTableViewDataType] ];
	[cannotGiveTableView registerForDraggedTypes: [NSArray arrayWithObject:MyPrivateTableViewDataType] ];
		
	sranddev();
}

- (NSString *)windowNibName 
{
    return @"MyDocument";
}

- (void)windowControllerDidLoadNib:(NSWindowController *)windowController 
{
    [super windowControllerDidLoadNib:windowController];
    // user interface preparation code
}

- (void) setChristmas:(SSChristmas *)value
{
	if(value != christmas)
	{
		[christmas release];
		christmas = [value retain];
	}
}

- (SSChristmas *) christmas
{
	if(christmas != nil) return christmas;
	
	NSManagedObjectContext *moc = [self managedObjectContext];
	NSError *fetchError = nil;
	NSArray *fetchResults;
	NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
	
	@try 
	{
		NSEntityDescription *entity = [NSEntityDescription entityForName:@"Christmas" inManagedObjectContext:moc];
		[fetchRequest setEntity:entity];
		fetchResults = [moc executeFetchRequest:fetchRequest error:&fetchError];
	} 
	@finally 
	{
		[fetchRequest release];
	}
	
	if ((fetchResults != nil) && ([fetchResults count] == 1) && (fetchError == nil)) 
	{
		//no error and only one christmas
		[self setChristmas:[fetchResults objectAtIndex:0]];
		return christmas;
	}
	
	if (fetchError != nil) 
	{
		[self presentError:fetchError];
	}
	else 
	{
		//custom error...
	}
	return nil;
	
}

- (id)initWithType:(NSString *)type error:(NSError **)error 
{
    self = [super initWithType:type error:error];
    if (self != nil) 
	{
		NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
		[[managedObjectContext undoManager] disableUndoRegistration];	//turn off undo
		
		//Create christmas.
		[self setChristmas:[NSEntityDescription insertNewObjectForEntityForName:@"Christmas" 
														 inManagedObjectContext:managedObjectContext]];
		
		[managedObjectContext processPendingChanges];
		[[managedObjectContext undoManager] enableUndoRegistration]; //turn undo back on
    }
    return self;
}

//
// Actions
//
- (IBAction) prepareMatches: (id) sender
{
	if(NO == [[self christmas] prepareMatches])
	{
		NSAlert *alert = [NSAlert alertWithMessageText: @"Sorry..."
										 defaultButton: @"OK" 
									   alternateButton: nil
										   otherButton: nil
							 informativeTextWithFormat: @"Santa cant find a combination that meets your requirements. Please examine your constraints and try again." ];
		
		[alert setIcon: [NSImage imageNamed: @"santa_reading"]];
		
		[alert beginSheetModalForWindow: [personTableView window]
						  modalDelegate: self
						 didEndSelector: nil
							contextInfo: nil];
	}
	else
	{
		[christmas setPrepared: [NSNumber numberWithBool:YES]];
	}
}

- (BOOL) prepared
{
	return prepared;
}

//
// Drag and Drop
//


/**
 * This method is called as the document is registeres as the Data Source for the 
 * NSTableView used as the list of people.
 */
- (BOOL)	tableView:(NSTableView *)tv 
 writeRowsWithIndexes:(NSIndexSet *)rowIndexes 
		 toPasteboard:(NSPasteboard*)pboard
{
	if(tv == cannotGiveTableView) return NO;
	
	// Copy the row numbers to the pasteboard.
	
	NSLog(@"Starting Drag with %d", [rowIndexes firstIndex]);
	
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
	
    [pboard declareTypes:[NSArray arrayWithObject:MyPrivateTableViewDataType] owner:self];
	
    [pboard setData:data forType:MyPrivateTableViewDataType];
	
    return YES;
}

- (NSDragOperation)tableView:(NSTableView*)tv 
				validateDrop:(id <NSDraggingInfo>)info
				 proposedRow:(int)row
	   proposedDropOperation:(NSTableViewDropOperation)op
{
	if (tv == personTableView) return NSDragOperationNone;
	
	return NSDragOperationEvery;
}

- (BOOL)tableView:(NSTableView *)aTableView 
	   acceptDrop:(id <NSDraggingInfo>)info
			  row:(int)row 
	dropOperation:(NSTableViewDropOperation)operation
{
    NSPasteboard* pboard = [info draggingPasteboard];
    NSData* rowData = [pboard dataForType:MyPrivateTableViewDataType];
    NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];
	
    int dragRow = [rowIndexes firstIndex];
	NSLog(@"Starting Drop with %d", dragRow);
	
	SSPerson *person = [[personArrayController selectedObjects] objectAtIndex: 0];
	SSPerson *dropped = [[personArrayController arrangedObjects] objectAtIndex: dragRow];
	
	NSLog(@" - Drop on %@  - Dropped %@", [person name], [dropped name]);
	
	[person addCannotGiveToObject: dropped];
		
	return YES;	
}

//Table view delegated method
- ( void ) deleteKeyPressed: ( NSTableView * ) view onRow: ( int ) rowIndex;
{
	if(view == personTableView)
	{
		[personArrayController remove: self];
	}
	else if(view == cannotGiveTableView)
	{
		SSPerson *personSelected = [[personArrayController selectedObjects] objectAtIndex: 0];
		SSPerson *personToRemove = [[cannotGiveArrayController arrangedObjects] objectAtIndex: rowIndex];
		
		[personSelected removeCannotGiveToObject: personToRemove];
		
		//[cannotGiveArrayController remove: self];
	}
}

- (void) progressUpdate
{
	[NSApp runModalSession: session];
	
	[[NSRunLoop currentRunLoop] runUntilDate:
        [NSDate dateWithTimeIntervalSinceNow:0.1]];
}

- (IBAction) sendEmail: (id) sender;
{
	NSLog(@"Starting to send mail");
	if(NO == [NSMailDelivery hasDeliveryClassBeenConfigured])
	{
		NSAlert *alert = [NSAlert alertWithMessageText: @"Configure Mail"
										 defaultButton: @"OK" 
									   alternateButton: nil
										   otherButton: nil
							 informativeTextWithFormat: @"Please configure Mail so that Santa can send the Christmas messages." ];
		
		[alert setIcon: [NSImage imageNamed: @"Santa Present"]];
		
		[alert beginSheetModalForWindow: [personTableView window]
						  modalDelegate: self
						 didEndSelector: nil
							contextInfo: nil];		
		return;
	}
	else
	{
		[NSApp beginSheet: sendingMailPanel
		   modalForWindow: [personTableView window]
			modalDelegate: self
		   didEndSelector: nil
			  contextInfo: nil];
		
		session = [NSApp beginModalSessionForWindow: sendingMailPanel];

		[christmas sendEmailWithStatus: self];

		[NSApp endModalSession: session];
		[NSApp endSheet: sendingMailPanel];
		[[NSSound soundNamed:@"Glass"] play];
		[sendingMailPanel orderOut: self];
	}
}

- (NSArray *) statusMessages
{
	return statusMessages;
}

- (void) clearStatus
{
    NSSet *changedObjects = [[NSSet alloc] initWithArray:statusMessages];
    
    [self willChangeValueForKey:@"statusMessages" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    
	[statusMessages removeAllObjects];
    
    [self didChangeValueForKey:@"statusMessages" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    
    [changedObjects release];	
}

- ( void ) setIncrementCountTo: (int) value
{
	[self clearStatus];
		
	[progressBar setIndeterminate: NO];
	[progressBar setMinValue: 0.0];
	[progressBar setMaxValue: value];
	[progressBar setDoubleValue: 0.0];
}

- ( void ) incrementProgress
{
	[progressBar setDoubleValue: [progressBar doubleValue] + 1.0];
	[self progressUpdate];
}

- ( void ) addStatus: ( NSString * ) message
{
	SSStatusMessage *value = [[[SSStatusMessage alloc] init] autorelease];
	
	[value setMessage: message];
	
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    
    [self willChangeValueForKey:@"statusMessages" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    
    [statusMessages insertObject:value atIndex: 0];
    
    [self didChangeValueForKey:@"statusMessages" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    
    [changedObjects release];
	
	[self progressUpdate];
}

- ( void ) changeStatus: ( BOOL ) success
{
	[[statusMessages objectAtIndex:0] setSuccess: success];
	
	if(NO == success)
	{
		[[NSSound soundNamed:@"Basso"] play];
	}
	
	[self progressUpdate];
}

@end
